home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 February: Tool Chest / Dev.CD Feb 99 TC.toast / What's New? / Development Kits / Mac OS USB v1.1f3 DDK / Examples / PrinterClassDriver / Chooser.cp next >
Encoding:
Text File  |  1999-01-07  |  32.5 KB  |  1,141 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Chooser.cp
  3.  
  4.     Contains:    Chooser PACK code to support USB and serial printers
  5.  
  6.     Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  7.  
  8. */
  9.  
  10. #ifndef __Chooser__
  11. #include "Chooser.h"
  12. #endif
  13.  
  14. #ifndef __COMMON__
  15. #include "Common.h"
  16. #endif
  17.  
  18. #ifndef __UTILS__
  19. #include "Utils.h"
  20. #endif
  21.  
  22. #ifndef __DEVICES__
  23. #include <Devices.h>
  24. #endif
  25.  
  26. #ifndef __RESOURCES__
  27. #include <Resources.h>
  28. #endif
  29.  
  30. #ifndef __TEXTUTILS__
  31. #include <TextUtils.h>
  32. #endif
  33.  
  34. #ifndef __COMMRESOURCES__
  35. #include <CommResources.h>
  36. #endif
  37.  
  38. #ifndef __CRMSERIALDEVICES__
  39. #include <CRMSerialDevices.h>
  40. #endif
  41.  
  42. #ifndef __MIXEDMODE__
  43. #include <MixedMode.h>
  44. #endif
  45.  
  46. #ifndef __CODEFRAGMENTS__
  47. #include <CodeFragments.h>
  48. #endif
  49.  
  50. #ifndef __DIALOGS__
  51. #include <dialogs.h>
  52. #endif
  53.  
  54. #ifndef __SafeNameRegistry__
  55. #include "SafeNameRegistry.h"
  56. #endif
  57.  
  58. /******************************************************************************
  59.     Typedefs
  60.  ******************************************************************************/
  61.  
  62. // This structure is passed to AddPrintertoList (a callback routine) from
  63. // SearchForUSBPrinters. Its used to hold data which is needed to add a
  64. // printer name to the Chooser's printer list
  65. typedef struct
  66. {
  67.     ListHandle    list;            // the printer list
  68.     Cell        insertcell;        // where to insert an entry
  69.     short        modelIndex;        // index into STR# holding printer models supported
  70. } AddPrintertoListCallBackStruct, *AddPrintertoListCallBackStructPtr;
  71.  
  72. // This structure is passed to AddPorttoList (a callback routine) from
  73. // SearchForSerialPorts. Its used to hold data which is needed to add a
  74. // serial port to the Chooser's printer list
  75. typedef struct
  76. {
  77.     ListHandle    list;            // the printer list
  78.     Cell        insertcell;        // where to insert an entry
  79. } AddPorttoListCallBackStruct, *AddPorttoListCallBackStructPtr;
  80.  
  81. // typedef for callback routine used in SearchForUSBPrinters when a printer
  82. // entry is found in the name registry
  83. typedef void (*FoundUSBPrinterProcPtr) ( RegEntryID* aPrinterEntry, void* userData);
  84.  
  85. // typedef for callback routine used in SearchForSerialPorts when a port
  86. // entry is found in the name registry
  87. typedef void (*FoundSerialPortProcPtr) ( CRMSerialPtr aPort, void* userData);
  88.  
  89. /******************************************************************************
  90.     Prototypes
  91.  ******************************************************************************/
  92.  
  93. short    CountUSBPrinters(void);
  94. void    FillPrinterList( ListHandle list );
  95. void    AddPrintertoList( RegEntryID* aPrinterEntry, void* userData );
  96. void    CountAPrinter( RegEntryID* aPrinterEntry, void* userData );
  97. void    SearchForUSBPrinters( StringPtr modelPath, FoundUSBPrinterProcPtr callback, void* userData );
  98.  
  99. short    CountSerialPorts(void);
  100. void    AddPorttoList( CRMSerialPtr aPort, void* userData );
  101. void    CountAPort(  CRMSerialPtr aPort, void* userData );
  102. void    SearchForSerialPorts(FoundSerialPortProcPtr callback, void* userData);
  103.  
  104. OSErr    ShowSelection (ListHandle list, StringPtr zoneName);
  105. OSErr    Select (ListHandle list, StringPtr zoneName, long rowNum);
  106.  
  107. void    SetConnectionType(short    type);
  108. short    GetConnectionType(void);
  109. OSErr    InitPack(void);
  110.  
  111. Boolean    SaveSelectedUSBPrinter( Cell selectedCell, ListHandle list );
  112. void    SaveSelectedPrinterName( Cell selectedCell, ListHandle list);
  113. Handle    GetLastSelectedUSBPrinter();
  114.  
  115. /******************************************************************************
  116.     Constants
  117.  ******************************************************************************/
  118.  
  119. #define        kHilited    0
  120. #define        kUnHilited    255
  121.  
  122. #define        kGlobalType        'wxyz'        // made up type
  123. #define        kGlobalID        128
  124.  
  125. #define        kConnectionType        'CTYP'
  126. #define        kConnectionTypeID    1000
  127.  
  128. // Possible selected types. Used in ConnectionType rsrc
  129. #define        kNone            0
  130. #define        kSerial            1
  131. #define        kUSB            2
  132.  
  133. #define     kAPortName    "\p.AIn"    // To compare input device name when searching serial devices in the Comm Tool Box's List
  134. #define        kBPortName    "\p.BIn"    // To comapre input device name when searching serial devices in the Comm Tool Box's List
  135.  
  136. #define        kPrinterNotAvailable    3100
  137. /*-----------------------------------------------------------------------------*
  138.  
  139.     SaveSelectedUSBPrinter
  140.     
  141.     Desc:        Saves the name registry path of the selected printer
  142.  
  143.     In:            - the cell of the selected printer
  144.                 - the Chooser's printer list
  145.                 - the row of the selected cell
  146.                 
  147.     Out:        true if the path was saved
  148.                 false if the path wasn't saved
  149.  
  150.     History:
  151.     
  152.     21 Apr 98    gp        Created
  153.     
  154.  *-----------------------------------------------------------------------------*/
  155. Boolean    SaveSelectedUSBPrinter( Cell selectedCell, ListHandle list )
  156. {
  157.     Handle        lastPrinterString=nil;    // the previous selected printer 
  158.     Str255         selectedPrinterName;    // name of the selected printer
  159.     Str255        modelString;    // path in name registry of printer model
  160.     Boolean        saved=false;            // was the selected printer saved properly
  161.  
  162.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  163.  
  164.     gGlobals = GetGlobalStorage();
  165.  
  166.     // Get the name of the printer that was selected out of the list
  167.     GetNameFromCell (selectedPrinterName, selectedCell, list);
  168.     // get the last selected printer
  169.     lastPrinterString = GetLastSelectedUSBPrinter();
  170.  
  171.     // get the model path
  172.     GetIndString(modelString, kUSBModelPathString, *((**gGlobals).modelIndex+selectedCell.v) );
  173.     if( modelString[0] != 0 && lastPrinterString != nil) 
  174.     {                
  175.         Handle    tempHandle=nil;
  176.         // create the selected printer's name registry path
  177.         AppendPStr( (StringPtr) modelString, "\p:" );
  178.         AppendPStr( (StringPtr) modelString, selectedPrinterName );
  179.         
  180.         HLock( lastPrinterString );
  181.         BlockMove( modelString, *lastPrinterString, modelString[0]+1 );
  182.         HUnlock( lastPrinterString );
  183.  
  184.         // save the selected printers's name registry path
  185.         ChangedResource( lastPrinterString );
  186.         SetConnectionType( kUSB );
  187.         
  188.         WriteResource(lastPrinterString);
  189.         saved = true;
  190.     }
  191.     return saved;
  192. }
  193.  
  194. /*-----------------------------------------------------------------------------*
  195.  
  196.     GetLastSelectedUSBPrinter
  197.     
  198.     Desc:        Returns the name registry path of the last selected USB printer
  199.  
  200.     In:            None
  201.                 
  202.     Out:        Handle to a STR containing the name registry path of the last
  203.                 selected USB printer
  204.  
  205.     History:
  206.     
  207.     21 Apr 98    gp        Created
  208.     
  209.  *-----------------------------------------------------------------------------*/
  210. Handle    GetLastSelectedUSBPrinter()
  211. {
  212.     Handle            printerString=nil;    // the full path in name registry of last selected USB printer
  213.  
  214.     printerString = Get1Resource( 'STR ', kUSBPrinterPathString );
  215.     if( printerString == nil ) {
  216.         DebugStr("\pIn GetLastSelectedUSBPrinter. THIS SHOULD NEVER HAPPEN");
  217.     }
  218.     return printerString;
  219. }
  220.  
  221. /*-----------------------------------------------------------------------------*
  222.  
  223.     SaveSelectedPrinterName
  224.     
  225.     Desc:        Saves the name of the selected printer in our rsrc
  226.  
  227.     In:            - the cell of the selected printer
  228.                 - the Choosers printer list handle
  229.                 
  230.     Out:        None
  231.  
  232.     History:
  233.     
  234.     21 Apr 98    gp        Created
  235.     
  236.  *-----------------------------------------------------------------------------*/
  237. void    SaveSelectedPrinterName( Cell selectedCell, ListHandle list)
  238. {
  239.     Handle            printerString=nil;        // path in name registry of current USB printer
  240.     Str255             selectedPrinterName;            // name of the selected printer
  241.  
  242.     GetNameFromCell (selectedPrinterName, selectedCell, list);
  243.  
  244.     // save the name of the printer
  245.     printerString = (Handle) Get1Resource( 'STR ', kPrinterNameString );
  246.     if( selectedPrinterName[0] != 0 && printerString != nil) 
  247.     {
  248.         HLock( printerString );
  249.         BlockMove( selectedPrinterName, *printerString, selectedPrinterName[0]+1 );
  250.         HUnlock( printerString );
  251.  
  252.         // save the newly selected printer's name
  253.         ChangedResource( printerString );
  254.         WriteResource(printerString);
  255.     }
  256.  
  257. }
  258.  
  259. /*-----------------------------------------------------------------------------*
  260.  
  261.     GetConnectionType
  262.     
  263.     Desc:        Gets the connection type for the last selected printer
  264.                 from our rsrc
  265.  
  266.     In:            None
  267.                 
  268.     Out:        kNone, kSerial or kUSB
  269.  
  270.     History:
  271.     
  272.     27 Mar 98    gp        Created
  273.     
  274.  *-----------------------------------------------------------------------------*/
  275. short    GetConnectionType(void)
  276. {
  277.     Handle    connection;
  278.  
  279.     connection = (Handle) Get1Resource( kConnectionType, kConnectionTypeID );
  280.     return (**(short**)connection);
  281.  
  282. }
  283.  
  284. /*-----------------------------------------------------------------------------*
  285.  
  286.     SetConnectionType
  287.     
  288.     Desc:        Saves the connection type of the selected printer in our rsrc
  289.  
  290.     In:            kNone, kSerial or kUSB
  291.                 
  292.     Out:        None
  293.     
  294.     History:
  295.     
  296.     27 Mar 98    gp        Created
  297.     
  298.  *-----------------------------------------------------------------------------*/
  299. void    SetConnectionType(short    type)
  300. {
  301.     Handle    connection;
  302.  
  303.     connection = (Handle) Get1Resource( kConnectionType, kConnectionTypeID );
  304.     (**(short**)connection) = type;
  305.     ChangedResource( connection );
  306.     WriteResource( connection );
  307. }
  308.  
  309. /*-----------------------------------------------------------------------------*
  310.  
  311.     CountAPort
  312.     
  313.     Desc:        Callback routine for CountSerialPorts. It increments the
  314.                 ptr to user data thus incrementing the count of serial ports.
  315.  
  316.     In:            - A port to a CRMSerialPtr struct
  317.                 - A ptr to user data
  318.  
  319.     Out:        None
  320.     
  321.     History:
  322.     
  323.     26 Mar 98    gp        Created
  324.     
  325.  *-----------------------------------------------------------------------------*/
  326. void    CountAPort(  CRMSerialPtr aPort, void* userData )
  327. {
  328.     // we're only interested in .ain and .bin
  329.     if ( (PStrEqualCaseInsensitive((unsigned char*) kBPortName, *(aPort->inputDriverName)) ) ||
  330.         (PStrEqualCaseInsensitive((unsigned char*) kAPortName, *(aPort->inputDriverName)) ))
  331.     {
  332.             *((short*) userData) +=1;
  333.     }
  334. }
  335.  
  336. /*-----------------------------------------------------------------------------*
  337.  
  338.     AddPorttoList
  339.     
  340.     Desc:        Adds a serial port the the Chooser's list. We're only interested
  341.                 in modem and printer ports
  342.  
  343.     In:            - A port to a CRMSerialPtr struct
  344.                 - A ptr to user data. This should be a ptr to a 
  345.                   AddPorttoListCallBackStruct
  346.  
  347.     Out:        None
  348.     
  349.     History:
  350.     
  351.     26 Mar 98    gp        Created
  352.     
  353.  *-----------------------------------------------------------------------------*/
  354. void    AddPorttoList( CRMSerialPtr aPort, void* userData )
  355. {
  356.     AddPorttoListCallBackStructPtr     addPortStruct=(AddPorttoListCallBackStructPtr) userData;
  357.  
  358.     // we're only interested in .ain and .bin
  359.     if ( PStrEqualCaseInsensitive((unsigned char*) kBPortName, *(aPort->inputDriverName)) )
  360.     {
  361.         LAddRow(1, addPortStruct->insertcell.v, addPortStruct->list);
  362.         LSetCell( "Printer", 7, addPortStruct->insertcell, addPortStruct->list );
  363.         addPortStruct->insertcell.v++;
  364.     }
  365.     
  366.     if ( PStrEqualCaseInsensitive((unsigned char*) kAPortName, *(aPort->inputDriverName)) )
  367.     {
  368.         LAddRow(1, addPortStruct->insertcell.v, addPortStruct->list);
  369.         LSetCell( "Modem", 5, addPortStruct->insertcell, addPortStruct->list );
  370.         addPortStruct->insertcell.v++;
  371.     }
  372. }
  373.  
  374. /*-----------------------------------------------------------------------------*
  375.  
  376.     CountSerialPorts
  377.     
  378.     Desc:        Returns the number of serial ports
  379.  
  380.     In:            None
  381.                 
  382.     Out:        The number of serial ports
  383.     
  384.     History:
  385.     
  386.     26 Mar 98    gp        Created
  387.     
  388.  *-----------------------------------------------------------------------------*/
  389. short    CountSerialPorts(void)
  390. {
  391.     short    numberOfPorts=0;
  392.  
  393.     SearchForSerialPorts( (FoundSerialPortProcPtr) &CountAPort, &numberOfPorts );
  394.  
  395.     return numberOfPorts;
  396. }
  397.  
  398. /*-----------------------------------------------------------------------------*
  399.  
  400.     SearchForSerialPorts
  401.     
  402.     Desc:        Searchs for serial ports on this machine
  403.  
  404.     In:            - A callback routine which gets called when a printer is found
  405.                 - A ptr to user data
  406.  
  407.     Out:        None
  408.     
  409.     History:
  410.     
  411.     26 Mar 98    gp        Created
  412.     
  413.  *-----------------------------------------------------------------------------*/
  414. void    SearchForSerialPorts(FoundSerialPortProcPtr callback, void* userData)
  415. {
  416.     CRMErr                theErr;                // comm rsrc manager error
  417.     CRMRec                commRec;            // communications resource manager record
  418.     CRMRecPtr            commRecPtr;            // ptr to a communication resource record in the queue
  419.     CRMSerialPtr        commRecSerialPtr;    // ptr to serial record inside comm resource record
  420.     long            curSerialDeviceID = 0;     // initially set to zero, so we get all serial devices
  421.  
  422.     theErr = InitCRM(); // Initialize the Communications Resource Manager
  423.  
  424.     // now search for serial devices
  425.     while (theErr == noErr)
  426.     {
  427.         commRec.crmDeviceType = crmSerialDevice; // look for serial devices
  428.         commRec.crmDeviceID = curSerialDeviceID; // look for a device number greater than curSerialDeviceID
  429.     
  430.         commRecPtr = &commRec;
  431.         commRecPtr = CRMSearch(commRecPtr);    // Search  queue for each serial device
  432.     
  433.         if (commRecPtr != nil)
  434.         {
  435.             // get the Serial record pointer
  436.             commRecSerialPtr = (CRMSerialPtr)(*commRecPtr).crmAttributes;
  437.             
  438.             callback( commRecSerialPtr, userData);    // found a port
  439.             
  440.             // Set device ID for next search
  441.             curSerialDeviceID = (*commRecPtr).crmDeviceID;
  442.         }
  443.         else
  444.         {
  445.             theErr = 1; // game over, no more serial devices
  446.         }
  447.     }
  448. }
  449.  
  450. /*-----------------------------------------------------------------------------*
  451.  
  452.     SearchForUSBPrinters
  453.     
  454.     Desc:        Searches thru a printer model entry in the name registry
  455.                 looking for a model's printers. When one is found a call is 
  456.                 issued to the clients callback routine for further processing
  457.  
  458.     In:            - A pstring full path in the name registry of a printer model
  459.                 - A callback routine which gets called when a printer is found
  460.                 - A ptr to user data
  461.                 
  462.     Out:        None
  463.     
  464.     History:
  465.     
  466.     24 Feb 98    gp        Created
  467.     
  468.  *-----------------------------------------------------------------------------*/
  469. void    SearchForUSBPrinters( StringPtr modelPath, FoundUSBPrinterProcPtr callback, void* userData )
  470. {
  471.  
  472.     RegEntryID        theModelEntry;        // the model node supported by the driver
  473.     RegEntryID        aPrinterEntry;        // a printer node in the name registry
  474.     RegEntryIterationOp iterOp;            // name registry iterator op code
  475.     RegEntryIter    printerIterator;    // used to iterate child nodes of printer model
  476.     Boolean            donePrinters    = false;    // NameRegistry param tell when we're done
  477.     OSStatus        err             = noErr;    // error from name registry calls
  478.  
  479.     // name registry only deals with c strings
  480.     p2cstr( (StringPtr) modelPath );
  481.  
  482.     // look up the node for the printer model requested
  483.     err = SafeRegistryEntryIDInit(&theModelEntry);
  484.     err = SafeRegistryCStrEntryLookup( nil, (char*) modelPath, &theModelEntry );
  485.  
  486.     if( err == noErr ) 
  487.     {
  488.         // create an iterator to look at the child nodes for our printer model entry
  489.         iterOp = kRegIterChildren;
  490.  
  491.         err = SafeRegistryEntryIterateCreate( &printerIterator );
  492.         err = SafeRegistryEntryIterateSet(&printerIterator, &theModelEntry);
  493.         
  494.         if( err == noErr )
  495.         {
  496.             // look for a model's connected printers
  497.             do
  498.             {
  499.                 err = SafeRegistryEntryIterate( &printerIterator, iterOp, &aPrinterEntry, &donePrinters );
  500.                 if( !donePrinters && err == noErr )
  501.                     callback(&aPrinterEntry, userData);    // found a printer
  502.  
  503.                 iterOp = kRegIterContinue;
  504.             } while( !donePrinters && err == noErr );
  505.             // end while for printers
  506.         }
  507.         SafeRegistryEntryIterateDispose(&printerIterator);
  508.     }
  509.  
  510.     SafeRegistryEntryIDDispose( &theModelEntry );
  511.     c2pstr( (char*) modelPath );
  512.  
  513. }
  514.  
  515. /*-----------------------------------------------------------------------------*
  516.  
  517.     CountAPrinter
  518.     
  519.     Desc:        Callback routine for CountUSBPrinters. It increments the
  520.                 ptr to user data thus incrementing the count of USB printers.
  521.  
  522.     In:            - A printer entry in the name registry
  523.                 - A ptr to user data
  524.                 
  525.     Out:        The number of USB printers in the name registry
  526.     
  527.     History:
  528.     
  529.     24 Feb 98    gp        Created
  530.     
  531.  *-----------------------------------------------------------------------------*/
  532.  
  533. void    CountAPrinter(  RegEntryID* aPrinterEntry, void* userData )
  534. {
  535.     *((short*) userData) +=1;
  536. }
  537.  
  538. /*-----------------------------------------------------------------------------*
  539.  
  540.     CountUSBPrinters
  541.     
  542.     Desc:        Returns the number of connected USB printers associated with this driver
  543.  
  544.     In:            None
  545.                 
  546.     Out:        The number of USB printers in the name registry
  547.     
  548.     History:
  549.     
  550.     24 Feb 98    gp        Created
  551.     
  552.  *-----------------------------------------------------------------------------*/
  553.  
  554. short    CountUSBPrinters()
  555. {
  556.     short            numberOfPrinters=0;    // return value for number of USB printers
  557.     Str255            modelPath;            // pstring path in a supported printer model
  558.     short            i;                    // counter
  559.  
  560.     i=1;
  561.     // read a supported printer's name registry model path
  562.     GetIndString(modelPath, kUSBModelPathString, i);
  563.     
  564.     while( (char*) modelPath[0] != 0 )        // if len is zero then no more models
  565.     {
  566.         SearchForUSBPrinters( modelPath, (FoundUSBPrinterProcPtr) &CountAPrinter, &numberOfPrinters );
  567.         i++;
  568.         // read another supported printer's name registry model path
  569.         GetIndString(modelPath, kUSBModelPathString, i);
  570.     }
  571.  
  572.     return numberOfPrinters;
  573. }
  574.  
  575. /*-----------------------------------------------------------------------------*
  576.  
  577.     AddPrintertoList
  578.     
  579.     Desc:        Adds an USB printer to the Chooser's printer list by extracting
  580.                 the name from the name registry
  581.  
  582.     In:            - A printer entry in the name registry
  583.                 - A ptr to user data. This should be a ptr to a 
  584.                   AddPrintertoListCallBackStruct 
  585.                 
  586.     Out:        The number of USB printers in the name registry
  587.     
  588.     History:
  589.     
  590.     24 Feb 98    gp        Created
  591.     
  592.  *-----------------------------------------------------------------------------*/
  593. void    AddPrintertoList( RegEntryID* aPrinterEntry, void* userData )
  594. {
  595.     OSStatus        err = noErr;        // error from name registry call
  596.     Str255            nodeName;            // the name of the printer
  597.     RegPropertyValueSize    nameSize;    // size of name buffer
  598.     AddPrintertoListCallBackStructPtr     fillListStruct=(AddPrintertoListCallBackStructPtr) userData;
  599.     USBGlobalsHandle    gGlobals=nil;    // our global data area
  600.  
  601.     gGlobals = GetGlobalStorage();
  602.  
  603.     nameSize = sizeof( nodeName );
  604.     // grab name of printer in name registyr
  605.     err = SafeRegistryPropertyGet( aPrinterEntry, "name", &nodeName, &nameSize );
  606.     
  607.     if( err == noErr ) {
  608.         // stick it in the printer list
  609.         LAddRow(1, fillListStruct->insertcell.v, fillListStruct->list);
  610.         LSetCell( nodeName, nameSize-1, fillListStruct->insertcell, fillListStruct->list );
  611.         
  612.         // save info about which model (STR#) this printer belongs to
  613.         *((**gGlobals).modelIndex+fillListStruct->insertcell.v) = fillListStruct->modelIndex;
  614.         fillListStruct->insertcell.v++;
  615.     }
  616. }
  617.  
  618. /*-----------------------------------------------------------------------------*
  619.  
  620.     FillUSBList
  621.     
  622.     Desc:        Fills the printer list with the number of USB printers
  623.  
  624.     In:            - The Chooser's printer list handle
  625.                 
  626.     Out:        None
  627.     
  628.     History:
  629.     
  630.     24 Feb 98    gp        Created
  631.     
  632.  *-----------------------------------------------------------------------------*/
  633. void    FillPrinterList( ListHandle list )
  634. {
  635.     AddPrintertoListCallBackStruct    userData;    // struct needed by callback routine
  636.     AddPorttoListCallBackStruct        userPortData;    // struct needed by callback routine
  637.     Str255        modelPath;                        // pstring path in a supported printer model
  638.     short        i;                                // counter
  639.  
  640.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  641.     
  642.     gGlobals = GetGlobalStorage();
  643.     
  644.     userPortData.insertcell.v = 0;
  645.     // if we support serial ports then list serial ports
  646.     if( (**gGlobals).supportsSerial == true ) {
  647.         userPortData.list = list;
  648.         userPortData.insertcell.h = 0;
  649.  
  650.         // add the serial ports to the chooser list
  651.         SearchForSerialPorts( (FoundSerialPortProcPtr) &AddPorttoList, (void*) &userPortData );
  652.     }
  653.  
  654.     // if we support USB then list USB printers
  655.     if( (**gGlobals).supportsUSB == true ) {
  656.         userData.list = list;
  657.         userData.insertcell.v = userPortData.insertcell.v;
  658.         userData.insertcell.h = 0;
  659.  
  660.         i=1;
  661.         // read a supported printer's name registry model path
  662.         GetIndString(modelPath, kUSBModelPathString, i);
  663.         while( (char*) modelPath[0] != 0 )        // if len is zero then no more models
  664.         {
  665.             userData.modelIndex = i;
  666.             // add the USB printers to the chooser list
  667.             SearchForUSBPrinters( modelPath, (FoundUSBPrinterProcPtr) &AddPrintertoList, (void*) &userData );
  668.             i++;
  669.             // read another supported printer's name registry model path
  670.             GetIndString(modelPath, kUSBModelPathString, i);
  671.         }
  672.     }
  673. }
  674.  
  675. /*-----------------------------------------------------------------------------*
  676.     
  677.     ShowSelection
  678.     
  679.     Desc:        Hilites the currently selected printer in the printer list
  680.  
  681.     In:            - Handle to Mac List Mgr list
  682.                 - Name of zone we are currently in
  683.                 
  684.     Out:        OS error if any
  685.     
  686.     History:
  687.     
  688.     21 Apr 98    gp        If only 1 USB printer is listed and no previous selection
  689.                         then select it. If previously selected printer is not available
  690.                         display an alert.
  691.     9  Apr 98    gp        Use hlock not hunlock. Moved foundcell outside loop
  692.     21 Mar 98    gp        Extract previously selected printer from our rsrc
  693.     24 Feb 98    gp        Created
  694.     
  695.  *-----------------------------------------------------------------------------*/
  696. OSErr    ShowSelection (ListHandle list, StringPtr zoneName)
  697. {
  698.     Cell            cell;                            // used to iterate thru printer list, shows selected cell
  699.     Str255            nameBuffer;                        // selected AT printer is on the net, search for the cell
  700.     Boolean            foundCell = false;                // found a cell with same name as selected printer
  701.     Handle            selectedPrinter;                // name of the selected printer
  702.  
  703.     Str255            modelString;                    // path in name registry of printer model
  704.     Handle            printerString;                    // the full path in name registry of selected USB printer
  705.     RegEntryID        thePrinterEntry;                // the node of the USB printer node selected
  706.     OSStatus        err             = noErr;        // err encountered when calling name registry API
  707.     short            hiliteState = kUnHilited;        // hilite state of the button
  708.     USBGlobalsHandle    gGlobals=nil;                // our global data area
  709.     short            connectionType;                    // what type of printer connection, serial or USB
  710.     
  711.     gGlobals = GetGlobalStorage();
  712.  
  713.     // get the current selected printer out of the rsrc
  714.     printerString = GetLastSelectedUSBPrinter();
  715.     if( printerString == nil ) {
  716.         return noErr;
  717.     }
  718.  
  719.     // extract printer name for use later
  720.     selectedPrinter = (Handle) Get1Resource( 'STR ', kPrinterNameString );
  721.     if(  selectedPrinter == nil)
  722.         return noErr;
  723.     HLock( selectedPrinter );
  724.  
  725.     connectionType = GetConnectionType();
  726.     switch( connectionType ) {
  727.         case kSerial:
  728.             SetPt (&cell, 0, 0);
  729.  
  730.             // look for the port
  731.             while ( (!foundCell) && (cell.v < (*list)->dataBounds.bottom) )
  732.             {
  733.                 GetNameFromCell(nameBuffer, cell, list);
  734.  
  735.                 // if it equals the name of the current cell, we found the printer
  736.                 if ( EqualString( (StringPtr) *selectedPrinter, nameBuffer, true, true) ) {
  737.                     foundCell = true;
  738.                 } else
  739.                     cell.v++;
  740.             }
  741.             if( !foundCell )
  742.                 StopAlert(kPrinterNotAvailable, nil);
  743.             break;
  744.         case kUSB:
  745.             HLock( printerString );
  746.  
  747.             // name registry only deals with c strings
  748.             p2cstr( (StringPtr) *printerString );
  749.  
  750.             // check to make sure printer is still in name registry before selecting
  751.             SafeRegistryEntryIDInit(&thePrinterEntry);
  752.             err = SafeRegistryCStrEntryLookup( nil, (char*) *printerString, &thePrinterEntry );
  753.             
  754.             // clean up
  755.             c2pstr( (char*) *printerString );
  756.             HUnlock( printerString );
  757.             SafeRegistryEntryIDDispose( &thePrinterEntry );
  758.  
  759.             // if printer is no longer connected put up an alert
  760.             if( err ) {
  761.                 StopAlert(kPrinterNotAvailable, nil);
  762.             } else {
  763.                 // since user could have connected or disconnect other printers from USB bus
  764.                 // we need to find the exact place in the list and hilite it
  765.  
  766.                 SetPt (&cell, 0, 0);
  767.  
  768.                 // loop through all the printers in the list seeing if there is a
  769.                 // match for the driver's selected printer
  770.                 while ( (!foundCell) && (cell.v < (*list)->dataBounds.bottom) )
  771.                 {
  772.                     GetNameFromCell(nameBuffer, cell, list);
  773.  
  774.                     // If the name is one of our reserved rows and
  775.                     // it equals the name of the current cell, we found a possible printer
  776.                     
  777.                     if ( EqualString( (StringPtr) *selectedPrinter, nameBuffer, true, true) ) {
  778.  
  779.                         // create name registry full path for this printer and compare it
  780.                         // to the one thats stored in our rsrc
  781.                         
  782.                         // get the printers model
  783.                         GetIndString(modelString, kUSBModelPathString, *((**gGlobals).modelIndex+cell.v) );
  784.                         if( modelString[0] != 0 ) 
  785.                         {
  786.                             // create the path
  787.                             AppendPStr( (StringPtr) modelString, "\p:" );
  788.                             AppendPStr( (StringPtr) modelString, nameBuffer );
  789.                             // check to see if its the same
  790.                             HLock( printerString );
  791.                             if ( EqualString( modelString, (StringPtr) *printerString, true, true) )
  792.                                 foundCell = true;
  793.                             HUnlock( printerString );
  794.                         }
  795.                     }
  796.  
  797.                     if (!foundCell)
  798.                         cell.v++;
  799.                 } // end while
  800.             } // end else
  801.             break;
  802.         default:
  803.             break;
  804.     }
  805.     HUnlock( selectedPrinter );
  806.  
  807.     // if this is our first time and only 1 entry in the list and its USB then select it
  808.     if( ((**gGlobals).supportsUSB == true) && !foundCell && 
  809.         ((*list)->dataBounds.bottom == 1) && ((**gGlobals).numberOfUSBPrinters == 1) ) 
  810.     {
  811.         if( printerString != nil && (**printerString) == 0x0) {
  812.             SetPt(&cell, 0, 0);        // select the 1st cell
  813.  
  814.             if( SaveSelectedUSBPrinter( cell, list ) ) {
  815.                 // save the name of the printer
  816.                 SaveSelectedPrinterName( cell, list );
  817.                 foundCell = true;
  818.             }
  819.         }
  820.     }
  821.  
  822.     // now hilite the selection
  823.     if (foundCell)
  824.     {
  825.         LSetSelect(true, cell, list);
  826.         hiliteState = kHilited;
  827.     }
  828.  
  829.  
  830.     return noErr;
  831. }
  832.  
  833. /*-----------------------------------------------------------------------------*
  834.  
  835.     Select
  836.     
  837.     Desc:        Save the selected printers name and name registry path in our rsrc
  838.  
  839.     In:            - Handle to Mac List Mgr list
  840.                 - Name of zone we are currently in
  841.                 - the row Chooser thinks we should select.
  842.                 
  843.     Out:        OS error if any
  844.     
  845.     History:
  846.     
  847.     21 Mar 98    gp        Save printer name in our rsrc
  848.     24 Feb 98    gp        Created
  849.  
  850. *-----------------------------------------------------------------------------*/
  851. OSErr    Select (ListHandle list, StringPtr zoneName, long rowNum)
  852. {
  853.     
  854.     Str255            modelString;            // path in name registry of printer model
  855.     Handle            printerString=nil;        // path in name registry of current USB printer
  856.     Cell            selectedCell;            // for list processing
  857.     Str32            selectedPrinterName;    // select printer in list
  858.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  859.  
  860.     gGlobals = GetGlobalStorage();
  861.  
  862.     // Find out which row was selected
  863.     SetPt (&selectedCell, 0, 0);
  864.     LGetSelect (true, &selectedCell, list);
  865.  
  866.     // Get the name of the printer that was selected out of the list
  867.     GetNameFromCell (selectedPrinterName, selectedCell, list);
  868.  
  869.     // if nothing selected leave
  870.     if( selectedPrinterName[0] == 0 )
  871.         return noErr;
  872.  
  873.     // serial port selected so just clear the USB model path in the STR rsrc
  874.     if( selectedCell.v < (**gGlobals).numberOfPorts ) {
  875.         printerString = GetLastSelectedUSBPrinter();
  876.         (**printerString) = 0;
  877.         ChangedResource( printerString );
  878.         SetConnectionType( kSerial );
  879.         WriteResource(printerString);
  880.     } else {
  881.         SaveSelectedUSBPrinter( selectedCell, list );
  882.     }
  883.  
  884.     // save the name of the printer
  885.     SaveSelectedPrinterName( selectedCell, list );
  886.     return noErr;
  887. }
  888.  
  889. /*-----------------------------------------------------------------------------*
  890.  
  891.     InitPack
  892.     
  893.     Desc:        Creates our global storage and reads info out of our
  894.                 connection info rsrc
  895.  
  896.     In:            None
  897.  
  898.     Out:        OS error if any
  899.     
  900.     History:
  901.     
  902.     8  May 98    gp        If we don't support USB then no need to init the name registry
  903.                         ptrs. This will prevent the name registry alert from
  904.                         displaying on non PCI PowerMacs if we only support serial.
  905.     8  May 98    gp        Moved creation of model index to here from InitGlobalStorage
  906.     21 Apr 98    gp        If we don't support serial set numberOfPorts to zero
  907.     27 Mar 98    gp        Created
  908.  
  909.  *-----------------------------------------------------------------------------*/
  910. OSErr    InitPack(void)
  911. {
  912.     OSErr                returnValue            = noErr;    // return value
  913.     USBGlobalsHandle    gGlobals            = nil;        // our global data area
  914.     ConnectionTypeHdl    connectionInfo        = nil;
  915.     short                numberOfUSBPrinters = 0;        // number of USB printers detected
  916.     short                numberOfPorts        = 0;        // number of serial ports
  917.  
  918.     // initialize our global storage
  919.     returnValue = InitGlobalStorage();
  920.     if( returnValue == noErr ) 
  921.     {
  922.         gGlobals = GetGlobalStorage();
  923.         connectionInfo = (ConnectionTypeHdl) Get1Resource( kConnectionType, kConnectionTypeID );
  924.         if( connectionInfo != nil )
  925.         {
  926.             (**gGlobals).supportsSerial = ( (**connectionInfo).supportsSerial == 1 );
  927.             (**gGlobals).supportsUSB = ( (**connectionInfo).supportsUSB == 1 );
  928.  
  929.             // if we don't support serial ports then zero out serial port count
  930.             if( (**gGlobals).supportsSerial == false )
  931.                 (**gGlobals).numberOfPorts = 0;
  932.         }
  933.         
  934.         // count USB printers
  935.         if( (**gGlobals).supportsUSB == true )
  936.         {
  937.             // if we support USB we need to init proc ptrs before calling CountUSBPrinters
  938.             InitNameRegistryPtrs();
  939.  
  940.             numberOfUSBPrinters = CountUSBPrinters();
  941.             (**gGlobals).numberOfUSBPrinters = numberOfUSBPrinters;
  942.         } else {
  943.             numberOfUSBPrinters = 0;
  944.             (**gGlobals).numberOfUSBPrinters = 0;
  945.         }
  946.  
  947.         // count serial ports
  948.         if( (**gGlobals).supportsSerial == true ) {
  949.             numberOfPorts = CountSerialPorts();
  950.             (**gGlobals).numberOfPorts = numberOfPorts;
  951.         } else {
  952.             numberOfPorts = 0;
  953.             (**gGlobals).numberOfPorts = 0;
  954.         }
  955.  
  956.         // allocate our index storage
  957.         // there is index space for serial ports which are unused but make the code simpler
  958.         (**gGlobals).modelIndex = (short*) NewPtr( (numberOfPorts+numberOfUSBPrinters)*sizeof(short) );
  959.         if ( (**gGlobals).modelIndex == nil )
  960.         {
  961.             // no index storage so get rid of our globals too
  962.             RemoveGlobalStorage();
  963.             returnValue = memFullErr;
  964.         }
  965.  
  966.     }
  967.     return returnValue;
  968. }
  969.  
  970. /*-----------------------------------------------------------------------------*
  971.  
  972.     Chooser
  973.     
  974.     Desc:        Routines to handle calls from the Chooser
  975.  
  976.     In:            - message from chooser
  977.                 - application id
  978.                 - additional info (varies)
  979.                 - name of the appletalk zone
  980.                 - handle to device choices ( printers )
  981.                 - additional info (varies)
  982.  
  983.     Out:        OS error if any
  984.     
  985.     History:
  986.     
  987.     19 Mar 98    gp        Created
  988.  
  989.  *-----------------------------------------------------------------------------*/
  990. pascal    OSErr    Chooser (short message, short caller, StringPtr objName, StringPtr zoneName, long p1, long p2)
  991. {
  992.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  993.     OSErr returnValue = noErr;                // return value
  994.  
  995.     gGlobals = GetGlobalStorage();
  996.     switch (message)
  997.     {
  998.         case chooserInitMsg:
  999.             returnValue = InitPack();
  1000.             break;
  1001.         case fillListMsg:
  1002.             if( gGlobals != nil )
  1003.                 FillPrinterList( (ListHandle) p1 );
  1004.             break;
  1005.         case getSelMsg:
  1006.             if( gGlobals != nil )
  1007.                 ShowSelection ( (ListHandle)p1, zoneName);
  1008.             break;
  1009.         case selectMsg:
  1010.             if( gGlobals != nil )
  1011.                 Select ( (ListHandle)p1, zoneName, p2);
  1012.             break;
  1013.         case buttonMsg:
  1014.             break;
  1015.         case terminateMsg:
  1016.             RemoveNameRegistryPtrs();
  1017.             RemoveGlobalStorage();
  1018.             break;
  1019.         case deselectMsg:
  1020.             break;
  1021.         default:
  1022.             break;
  1023.     }
  1024.     return returnValue;
  1025. }
  1026.  
  1027. /*-----------------------------------------------------------------------------*
  1028.  
  1029.     InitGlobalStorage
  1030.     
  1031.     Desc:        Creates and stores a block of memory in our rsrc to be
  1032.                 used as global storage
  1033.  
  1034.     In:            none
  1035.  
  1036.     Out:        OS error if any
  1037.     
  1038.     History:
  1039.     
  1040.     10 Jun 98    gp        Lock our global area
  1041.     9  Jun 98    gp        Clear the handle when creating the global storage
  1042.                         Remove old global rsrc if its still there
  1043.     8  May 98    gp        Moved creation of model index to InitPack
  1044.     25 Mar 98    gp        Created
  1045.  
  1046.  *-----------------------------------------------------------------------------*/
  1047. OSErr    InitGlobalStorage(void)
  1048. {
  1049.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  1050.     Handle    globalrsrc;                        // handle to store our global data address
  1051.  
  1052.     // get rid of old global rsrc if its still there
  1053.     globalrsrc = (Handle) Get1Resource(kGlobalType, kGlobalID);
  1054.     if( globalrsrc != nil ) {
  1055.         RemoveResource( globalrsrc );
  1056.         DisposeHandle( globalrsrc );
  1057.     }
  1058.  
  1059.     // allocate our global storage
  1060.     gGlobals = (USBGlobalsHandle) NewHandleClear( sizeof( USBGlobals ) );
  1061.     globalrsrc = NewHandleClear( sizeof( Handle ) );
  1062.     if (gGlobals != nil) 
  1063.     {
  1064.         HLockHi( (Handle) gGlobals );
  1065.         // save our global handle address in our rsrc
  1066.         (** (Handle**) globalrsrc) = (char**) gGlobals;
  1067.         addresource( globalrsrc, kGlobalType, kGlobalID,(char*) "\p");
  1068.  
  1069.         return noErr;
  1070.     } else
  1071.         return memFullErr;
  1072. }
  1073.  
  1074. /*-----------------------------------------------------------------------------*
  1075.  
  1076.     GetGlobalStorage
  1077.     
  1078.     Desc:        Retrieves our global stoarge area
  1079.  
  1080.     In:            none
  1081.  
  1082.     Out:        Handle to our global storage
  1083.     
  1084.     History:
  1085.     
  1086.     25 Mar 98    gp        Created
  1087.  
  1088.  *-----------------------------------------------------------------------------*/
  1089. USBGlobalsHandle    GetGlobalStorage(void)
  1090. {
  1091.     Handle    ourRsrc=nil;                    // handle to ourselves
  1092.  
  1093.     ourRsrc = (Handle) Get1Resource(kGlobalType, kGlobalID);
  1094.     if( ourRsrc == nil )
  1095.         return nil;
  1096.     
  1097.     return (**(USBGlobalsHandle**)ourRsrc);
  1098. }
  1099.  
  1100. /*-----------------------------------------------------------------------------*
  1101.  
  1102.     RemoveGlobalStorage
  1103.     
  1104.     Desc:        Removes our global storage area
  1105.  
  1106.     In:            none
  1107.  
  1108.     Out:        Handle to our global storage
  1109.     
  1110.     History:
  1111.     
  1112.     9  Jun 98    gp        Dispose of our global rsrc after removing it
  1113.     26 Mar 98    gp        Release model index storage
  1114.     25 Mar 98    gp        Created
  1115.  
  1116.  *-----------------------------------------------------------------------------*/
  1117. void    RemoveGlobalStorage(void)
  1118. {
  1119.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  1120.     Handle                ourRsrc;
  1121.     
  1122.     gGlobals = GetGlobalStorage();
  1123.     if( gGlobals != nil ) {
  1124.         // dispose of index ptr
  1125.         
  1126.         if ( (**gGlobals).modelIndex != nil )
  1127.         {
  1128.             DisposePtr( (Ptr) (**gGlobals).modelIndex );
  1129.         }
  1130.              
  1131.         // remove our global handle
  1132.         HUnlock( (Handle) gGlobals );
  1133.         DisposeHandle( (Handle) gGlobals );
  1134.         // remove our rsrc for global address storage
  1135.         ourRsrc = (Handle) Get1Resource(kGlobalType, kGlobalID);
  1136.         RemoveResource( ourRsrc );
  1137.         DisposeHandle( ourRsrc );
  1138.     }
  1139. }
  1140. // eof
  1141.